package main

import (
	"context"
	"fmt"
	"github.com/gorilla/mux"
	"github.com/gorilla/websocket"
	"io"
	"kd_rewiew/receiveFile"
	"log"
	"net/http"
	"os"
	"time"
)

// 首先建立一个服务器端，进行处理客户端的数据
// 然后完成服务端主动向客户端传输时间、文本记录请求

/*
通义千问的改进意见：
定时任务修正：使用 time.Ticker 来替代原有的定时逻辑，确保定时任务可以周期性地执行。
错误处理优化：遇到错误时立即关闭连接并退出循环，防止资源泄露。
移除不必要的代码：简化了 HTTP 处理逻辑，移除了不必要的结构体和方法。
并发安全性和效率：避免了不必要的 goroutine 泄露，并且提高了代码的并发安全性。
*/

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin:     func(r *http.Request) bool { return true },
}

func main() {
	// 创建mux，路由管理选项
	r := mux.NewRouter()
	r.HandleFunc("/home", home)
	r.HandleFunc("/file", File)

	http.Handle("/ping", http.HandlerFunc(Pong))
	http.HandleFunc("/charge", charge)
	http.HandleFunc("/socket", wsHandler)

	http.Handle("/", UserPass(r))
	log.Println("listen on localhost:2025")
	fmt.Println("server on ws,home,pong,socket,charge,file")
	log.Fatal(http.ListenAndServe("localhost:2025", nil))
}

// UserPass 建立用户名、密码实现的验证的路由组
func UserPass(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if !GetFromData(r.Header.Get("username"), r.Header.Get("password")) {
			//if _, err := fmt.Fprintf(w, "take right username and password, ask again"); err != nil {
			//	return
			//}
			// 使用包含code的api进行处理
			http.Error(w, "UnAuthorized", http.StatusUnauthorized)
		}
		next.ServeHTTP(w, r)
	})
}

func GetFromData(username string, password string) bool {
	return false
}

// charge 发送收款码捏，属鼠开心捏！
func charge(w http.ResponseWriter, req *http.Request) {
	// 届时存储系统搭建好了进行从存储系统获取内容，而不是直接放在外部文件夹下
	http.ServeFile(w, req, "./hufeng.png")
}

// home 项目的home目录，后续可以根据项目设计定向到对应api
func home(w http.ResponseWriter, _ *http.Request) {
	if _, err := fmt.Fprintf(w, "nihao!"); err != nil {
		log.Println(err)
		return
	}
}

// Pong 应答前端/client的即时ping请求
func Pong(w http.ResponseWriter, _ *http.Request) {
	if _, err := fmt.Fprintf(w, "pong!"); err != nil {
		log.Println(err)
		return
	}
}

// wsHandler 进行升级为ws协议，并处理消息和定时发送消息，后续可以升级为即时消息聊天室
func wsHandler(w http.ResponseWriter, r *http.Request) {
	ctx, cancelFunc := context.WithCancel(context.Background())
	defer cancelFunc()
	fmt.Println("ws 激活")
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}
	defer func() {
		if err = conn.Close(); err != nil {
			log.Println(err)
			return
		}
	}()

	if err := conn.WriteMessage(1, []byte("快TM救救胡桃")); err != nil {
		log.Println(err)
		return
	}

	// 进行业务信息传输

	// 直接调用一个后端协程进行定时发送消息
	go func() {
		ticker := time.NewTicker(1 * time.Second)
		defer ticker.Stop()

		for {
			select {
			case <-ticker.C:
				// fmt.Println("ticker on!", time.Now())
				// fmt.Println(time.Now().Hour() == 21 && time.Now().Minute() == 28 && time.Now().Second() == 0)
				// 通知客户端
				if time.Now().Hour() == 21 && time.Now().Minute() == 28 && time.Now().Second() == 0 {
					fmt.Println("time on!", time.Now())
					if err := conn.WriteMessage(1, []byte("快TM救救胡桃")); err != nil {
						log.Println(err)
						return
					}
				}
			case <-ctx.Done():
				return
			}
		}
	}()

	for {
		messageType, p, err := conn.ReadMessage()
		if err != nil {
			log.Println(err)
			return
		}
		fmt.Println(time.Now(), messageType, p, string(p))
		ans := string(p) + " client"
		if err := conn.WriteMessage(messageType, []byte(ans)); err != nil {
			log.Println(err)
			return
		}
	}
}

// File 接收前端/client的文件，如md文件，进行文件解析、存储
func File(_ http.ResponseWriter, req *http.Request) {
	// 后续从配置文件中定义，作为一个系统的文件接收位置
	baseDataPlace := "/home/hufeng/GolandProjects/hufeng_review/receiveFile/"
	if req.Method == "POST" {
		fmt.Println("accept from client:", req.Body)
	}
	file, header, err := req.FormFile("uploader")
	if err != nil {
		log.Println(err)
		return
	}
	defer func() {
		if err = file.Close(); err != nil {
			log.Println(err)
			return
		}
	}()
	fmt.Println("success to accept from client", file, header.Filename)
	// 下面进行文件的获取并保存，创建一个文件保存客户端传来的文件
	out, err := os.Create(baseDataPlace + header.Filename)
	if err != nil {
		log.Println(err)
		return
	}
	// 我们进行一个文件（file的数据结构体）的关闭还是在验证失败之后进行，否则进行关闭的就是一个空指针
	defer func() {
		if err = out.Close(); err != nil {
			log.Println(err)
			return
		}
	}()
	_, err = io.Copy(out, file)
	if err != nil {
		log.Println(err)
	}
	fmt.Println("name", out.Name())
	// 收到客户端的文件，之后进行数据存储到数据库中
	err = receiveFile.ParseDoc(header.Filename)
	if err != nil {
		panic(err)
	}
}
